COMP3141
Software System Design and Implementation (18s1)

Code (Week 9)

Table of Contents

1 Existentially quantified types

{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE GADTs, StandaloneDeriving #-}


module ExistsEx where

data M where
  MC :: a -> M


-- we can create values of type M. As the content type
xs :: [M]
xs = [ MC 4, MC True, MC even]

-- we can never do anything with values of type M, as we 
-- can't 'unpack' them. The following function raises a type
-- error, as the type of x can't be known statically
-- unpack (MC x) = x


data MS where
  MSC :: Show a => a -> MS

deriving instance (Show MS)
-- note that the function 'even' can't be in the list now,
-- because it's type is not in the class Show
ys :: [MS]
ys = [ MSC 4, MSC True]

-- we still can't define unpack, but we can take x and apply 
-- show to it: now, it's clear what the result type of the 
-- function is, independent of the actual type of x
unpackAndShow :: MS -> String
unpackAndShow (MSC x) = show x

-- we can also bundle the value of type 'a' explicitly with a 
-- function which knows what to do with it
data MP where
  MPC :: a -> (a -> String) -> MP

-- For the values whose type is in the Show class, we just provide the 
-- their show function, for 'even' we provide a costumised
zs :: [MP]
zs = [ MPC 4    show , 
       MPC True show, 
       MPC even (\_ -> "the function \'even\'")]

unpackAndShowMP :: MP -> String
unpackAndShowMP (MPC x f) = f x

Shape example:

module Shapes where

class ShapeC a where
   perimeter :: a -> Double
   area      :: a -> Double

data Shape = forall a. ShapeC a => Shape a


data Circle    = Circle    Double
data Rectangle = Rectangle Double Double

-- add this instance so we can apply methods directly
instance ShapeC Shape where
  perimeter (Shape shape) = perimeter shape
  area      (Shape shape) = area      shape

-- additional instances can be defined anywhere 
instance ShapeC Circle where
  perimeter (Circle r) = 2 * pi * r
  area      (Circle r) = pi * r * r

instance ShapeC Rectangle where
  perimeter (Rectangle x y) = 2*(x + y)
  area      (Rectangle x y) = x * y




 -- smart constructors

circle :: Double -> Shape
circle r 
  | r > 0     =  Shape (Circle r)
  | otherwise = error "Circle with non-positive radius" 

rectangle :: Double -> Double -> Shape
rectangle x y 
  | x > 0 && y > 0 = Shape (Rectangle x y)
  | otherwise      = error "Rectangle with non-positive side length"

shapes :: [Shape]
shapes = [circle 12, circle 10, rectangle 5 6]

2018-06-14 Thu 18:29

Announcements RSS